package com.wg.net.codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;

import com.wg.net.NetConfig;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;

/**
 * 基于长度字段的TCP粘包/拆包解码器（优化版）
 * <p>
 * 协议格式要求：
 * <pre>
 * +----------------+-------------------+
 * | 长度头（4字节）  |    数据体（N字节）  |
 * +----------------+-------------------+
 * </pre>
 * - 长度头：位于数据报文起始位置（偏移量0），占4字节（大端序int类型），表示数据体的字节长度（不含长度头自身）
 * - 数据体：长度由长度头指定，为实际需要传递的业务数据
 *
 * @author 少爷123
 */
public class MyDecoder extends LengthFieldBasedFrameDecoder {
    private static final Log log = LogFactory.get();

    /**
     * 默认最大帧长度（1MB），可根据业务需求调整
     */
    private static final int DEFAULT_MAX_FRAME_LENGTH = NetConfig.getInstance().getMaxFrameLength();


    /**
     * 构造一个基于长度字段的解码器（使用默认最大帧长度）
     */
    public MyDecoder() {
        this(DEFAULT_MAX_FRAME_LENGTH);
    }

    /**
     * 构造一个基于长度字段的解码器（自定义最大帧长度）
     *
     * @param maxFrameLength 允许的最大帧长度（包含长度头和数据体），需大于长度头长度（4字节）
     */
    public MyDecoder(int maxFrameLength) {
        /*
         * 参数说明（LengthFieldBasedFrameDecoder 构造函数）：
         * maxFrameLength    : 允许的最大帧长度（超过此长度会触发 TooLongFrameException）
         * lengthFieldOffset : 长度字段在数据报文中的偏移量
         * lengthFieldLength : 长度字段自身的长度（4字节，对应int类型）
         * lengthAdjustment  : 长度调整值（长度字段值 = 数据体长度 → 调整值为0）
         * initialBytesToStrip : 解码后需要跳过的字节数（跳过长度头4字节，仅保留数据体）
         */
        super(maxFrameLength, 0, 4, 0, 4);
    }

    /**
     * 重写解码逻辑，添加日志追踪和异常处理
     *
     * @param ctx 上下文对象
     * @param in  输入ByteBuf
     * @return 解码后的完整数据帧（数据体部分）
     * @throws Exception 解码过程中发生的异常（如帧过长、数据不完整等）
     */
    @Override
    protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        // 记录解码前的可读字节数（调试用）
        int readableBytesBefore = in.readableBytes();
        log.debug("开始解码，当前可读字节数: {}", readableBytesBefore);

        try {
            // 调用父类完成实际解码（基于长度字段提取完整数据帧）
            Object decodedFrame = super.decode(ctx, in);

            if (decodedFrame == null) {
                // 未解析出完整帧（等待后续数据）
                log.trace("数据不完整，继续等待后续字节（当前可读字节数: {}）", in.readableBytes());
                return null;
            }

            // 解码成功，记录关键指标
            if (log.isDebugEnabled()) {
                ByteBuf frameBuf = (ByteBuf) decodedFrame;
                int frameTotalLength = frameBuf.readableBytes() + 4;  // 总长度 = 数据体长度 + 长度头4字节
                log.debug("解码成功 | 原始数据体长度: {} | 总帧长度（含长度头）: {} | 当前可读剩余字节: {}",
                        frameBuf.readableBytes(), frameTotalLength, in.readableBytes());
                frameBuf.resetReaderIndex();  // 重置读指针（仅需记录日志，不影响后续处理）
            }

            return decodedFrame;

        } catch (Exception e) {
            // 捕获解码异常（如TooLongFrameException、CorruptedFrameException等）
            log.error("解码失败！当前可读字节数: {}，异常信息: {}", readableBytesBefore, e.getMessage(), e);

            // 触发异常传播（根据业务需求可选择关闭连接或继续处理）
            ctx.fireExceptionCaught(e);
            throw e;  // 向上抛出异常，终止当前解码流程
        }
    }
}